#!/bin/bash
#
# Copyright 2015-2017 Adrian DC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# === Sign Zip Package ===
function signzip()
{
  # Usage
  if [ ! -f "${1}" ]; then
    echo '';
    echo ' Usage: signzip <zip_to_sign> [signed_output_zip] (Sign flashable zip)';
    echo '';
    return;
  fi;

  # Variables
  local zip_input=${1};
  local zip_output=${2};
  local check_java;
  local check_javac;

  # Initialize variables
  check_java=$(java -version 2>&1 | grep 'version.*1\.' | cut -d"\"" -f 2 | cut -d'.' -f 2);
  check_javac=$(javac -version 2>&1 | grep '1\.' | cut -d' ' -f 2 | cut -d'.' -f 2);

  # Direct ZIP signature
  if [ -z "${zip_output}" ]; then
    zip_output=${zip_input};
    zip_input=$(readlink -f "${zip_input}.unsigned.zip");
    mv -v "${zip_output}" "${zip_input}";
  fi;

  # Apply the metadata file
  #local tmp_folder;
  #local pwd_folder;
  #tmp_folder=$(mktemp -d);
  #pwd_folder=$(pwd);
  #cd ${tmp_folder}/;
  #mkdir -p ./META-INF/com/android/;
  #echo 'ota-required-cache=0' > ./META-INF/com/android/metadata;
  #echo 'ota-type=FILE' >> ./META-INF/com/android/metadata;
  #echo 'post-build=' >> ./META-INF/com/android/metadata;
  #echo 'post-timestamp='$(date +%s) >> ./META-INF/com/android/metadata;
  #echo 'pre-device=' >> ./META-INF/com/android/metadata;
  #zip -d "${zip_input}" ./META-INF/com/android/metadata;
  #zip -g "${zip_input}" ./META-INF/com/android/metadata;
  #cd ${pwd_folder}/;

  # Remove output file
  rm -f "${zip_output}";

  # Check Java installed version
  if [ -z "${check_java}" ] || [ -z "${check_javac}" ] ||
     [ "${check_java}" -lt 7 ] || [ "${check_javac}" -lt 7 ]; then
    echo '';
    echo "  signzip: Current java version: '1.${check_java}' - javac: '1.${check_javac}'";
    echo '           Please install java[c] 1.7[1.7] or newer to use this command';
    echo '';
    return;
  fi;

  # Sign ZIP
  java -jar "${ANDROID_DEVELOPMENT_SHELL_TOOLS_SIGNAPK_DIR}/signapk-cm121.jar" \
      -w "${ANDROID_DEVELOPMENT_SHELL_TOOLS_SIGNAPK_DIR}/testkey.x509.pem" \
      "${ANDROID_DEVELOPMENT_SHELL_TOOLS_SIGNAPK_DIR}/testkey.pk8" \
      "${zip_input}" \
      "${zip_output}";

  # Remove unsigned file if successful
  if [ -f "${zip_input}" ]; then
    rm -f "${zip_input}";
  fi;
}

# === Sign Apk Package ===
function signapk()
{
  # Usage
  if [ ! -f "${1}" ]; then
    echo '';
    echo ' Usage: signapk <apk_to_sign> [signed_output_apk] (Sign apk files)';
    echo '';
    return;
  fi;

  # Reuse signzip for the same purpose
  signzip "${1}" "${2}";
}

# === Module Zip Maker ===
function mmmzip()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: mmmzip <paths_or_modules> (Build module to flashable zip)';
    echo '';
    return;
  fi;

  # Variables
  local BuildMode;
  local BuildParams;
  local BuildPathFirst;
  local CurDir;
  local FilesList=();
  local Installs;
  local LogFile;
  local OutFile;
  local path;
  local SystemPartition;
  local TargetFile;
  local TmpDir;

  # Initialize variables
  CurDir=$(pwd);
  TmpDir=$(mktemp -d);
  BuildParams=("${@:-.}");
  BuildPathFirst=${1:-.};
  LogFile=${TmpDir}/mmm_logs.txt;
  OutFile="pack-${TARGET_PRODUCT}-$(basename "$(readlink -f "${BuildPathFirst}")")-$(date +'%Y%m%d-%H%M').zip";
  path=$(readlink -f "${BuildPathFirst}");
  TargetFile="$(desktoppath)/Builds/${OutFile}";

  # Handle paths
  mkdir -p "$(dirname "${TargetFile}")";
  if [ ! -d "${path}" ]; then
    croot;
  fi;

  # Handle build mode
  BuildMode=-B;
  if [ "${MMMZIP_BUILD_PARTIAL}" = 'true' ]; then
    BuildMode=;
  fi;

  # Disable Ninja
  export USE_NINJA=false;
  export USE_SOONG_UI=false;

  # Header
  echo '';
  echo -e ' \e[1;37m[ Module Zip Maker by Adrian DC - 2016 ]\e[0m';
  echo '';
  echo '';

  # Make the modules
  if [ -d "$(readlink -f "${path}")" ]; then
    mmm "${BuildMode}" "${BuildParams[@]}" | tee "${LogFile}";
  elif mka -v > /dev/null 2>&1; then
    mka "${BuildParams[@]}" | tee "${LogFile}";
  else
    makes "${BuildParams[@]}" | tee "${LogFile}";
  fi;

  # Return to repo root
  croot;

  # Files handling
  Installs=$(grep "target/product/.*/system" "${LogFile}" | sort | uniq);
  for FilePath in ${Installs[*]}; do

    # Target selection
    if [[ "${FilePath}" == *'/system'* ]]; then
      FilePath=$(echo -n "${FilePath}" | tail -1 \
               | sed "s/\x1B\[[0-9;]*[JKmsu]//g" \
               | sed "s/.*\/\([^\[]*.zip\).*/\1/g");
      FileTarget=$(echo "${FilePath}" \
                 | sed "s/.*\(system\/.*\)/\1/g");
      FileDir=$(dirname "${FileTarget}"); 
      if [ ! -d "${TmpDir}/${FileDir}" ]; then
        mkdir -p "${TmpDir}/${FileDir}";
      fi;

      # Target copy
      if [ -f "${FilePath}" ]; then
        cp "${FilePath}" "${TmpDir}/${FileTarget}";
        FilesList+=("./${FileTarget}");
      fi;
    fi;
  done;

  # Pack zip output
  cd "${TmpDir}/";
  if [ ! -z "${FilesList[*]}" ]; then

    # Partitions
    SystemPartition=$(androiddevicestarget system);

    # Generate zip, updater-script and include files
    mkdir -p ./META-INF/com/google/android/;
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_FLASHABLE_ANDROID_BASE}" "${OutFile}.unsigned.zip";
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_UPDATER_INSTALL_SYSTEM}" ./META-INF/com/google/android/updater-script;
    sed -i "s/ANDROID_SYSTEM_PARTITION/${SystemPartition//\//\\\/}/" ./META-INF/com/google/android/updater-script;
    zip -g "${TmpDir}/${OutFile}.unsigned.zip" ./META-INF/com/google/android/updater-script;
    zip -g "${TmpDir}/${OutFile}.unsigned.zip" "${FilesList[@]}";
    rm -rf ./META-INF;

    # Zip signature
    signzip "${TmpDir}/${OutFile}.unsigned.zip" "${TmpDir}/${OutFile}";
    cp "${TmpDir}/${OutFile}" "${TargetFile}";
    export PACKAGE_RESULT=${TargetFile};

    # End of work
    echo '';
    echo -e " \e[1;37mPackage File:\e[0m ${TargetFile}";
  else
    export PACKAGE_RESULT=;
  fi;
  echo '';

  # Restore Ninja
  export USE_NINJA=;
  export USE_SOONG_UI=;

  # End of work
  rm -rf "${TmpDir}";
  cd "${CurDir}";
}

# === System Zip Maker ===
function systozip()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: systozip <files> (System files to flashable zip)';
    echo '';
    return;
  fi;

  # Variables
  local BuildParams=("${@:-.}");
  local BuildPathFirst=${1:-.};
  local CurDir;
  local FilesList=();
  local Installs;
  local LogFile;
  local OutFile;
  local path;
  local SystemPartition;
  local TargetFile;
  local TmpDir;

  # Initialize variables
  CurDir=$(pwd);
  TmpDir=$(mktemp -d);
  LogFile=${TmpDir}/mmm_logs.txt;
  OutFile="pack-${TARGET_PRODUCT}-$(basename "$(readlink -f "${BuildPathFirst}")")-$(date +'%Y%m%d-%H%M').zip";
  path=$(readlink -f "${BuildPathFirst}");
  TargetFile="$(desktoppath)/Builds/${OutFile}";

  # Handle paths
  mkdir -p "$(dirname "${TargetFile}")";

  # Header
  echo '';
  echo -e ' \e[1;37m[ System To Zip Maker by Adrian DC - 2016 ]\e[0m';
  echo '';

  # Files handling
  Installs=$(find "${BuildParams[@]}" -type f -printf '%P\n');
  for FilePath in ${Installs[*]}; do

    # Target selection
    FilePath=$(echo -n "${FilePath}" | tail -1 \
             | sed "s/\x1B\[[0-9;]*[JKmsu]//g" \
             | sed "s/.*\/\([^\[]*.zip\).*/\1/g");
    FileTarget=system/${FilePath};
    FileDir=$(dirname "${FileTarget}");
    if [ ! -d "${TmpDir}/${FileDir}" ]; then
      mkdir -p "${TmpDir}/${FileDir}";
    fi;

    # Target copy
    FilePath=$(readlink -f "${FilePath}");
    if [ -f "${FilePath}" ]; then
      cp "${FilePath}" "${TmpDir}/${FileTarget}";
      FilesList+=("./${FileTarget}");
    fi;
  done;

  # Pack zip output
  cd "${TmpDir}/";
  if [ ! -z "${FilesList[*]}" ]; then

    # Partitions
    SystemPartition=$(androiddevicestarget system);

    # Generate zip, updater-script and include files
    mkdir -p ./META-INF/com/google/android/;
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_FLASHABLE_ANDROID_BASE}" "${OutFile}.unsigned.zip";
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_UPDATER_INSTALL_SYSTEM}" ./META-INF/com/google/android/updater-script;
    sed -i "s/ANDROID_SYSTEM_PARTITION/${SystemPartition//\//\\\/}/" ./META-INF/com/google/android/updater-script;
    zip -g "${TmpDir}/${OutFile}.unsigned.zip" ./META-INF/com/google/android/updater-script;
    zip -g "${TmpDir}/${OutFile}.unsigned.zip" "${FilesList[@]}";
    rm -rf ./META-INF;

    # Zip signature
    signzip "${TmpDir}/${OutFile}.unsigned.zip" "${TmpDir}/${OutFile}";
    cp "${TmpDir}/${OutFile}" "${TargetFile}";
    export PACKAGE_RESULT=${TargetFile};

    # Package result
    echo '';
    echo -e " \e[1;37mPackage File:\e[0m ${TargetFile}";
  else
    export PACKAGE_RESULT=;
  fi;
  echo '';

  # End of work
  rm -rf "${TmpDir}";
  cd "${CurDir}";
}

# === Output Zip Maker ===
function packzip()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: packzip <files> (Files to flashable zip)';
    echo '';
    return;
  fi;

  # Variables
  local CurDir;
  local FilesList=();
  local FileTarget;
  local Installs;
  local OutFile;
  local SystemPartition;
  local TargetFile;
  local TmpDir;

  # Variables
  CurDir=$(pwd);
  TmpDir=$(mktemp -d);
  OutFile="pack-${TARGET_PRODUCT}-$(basename "$(readlink -f "${1}")")-$(date +'%Y%m%d-%H%M').zip";
  TargetFile="$(desktoppath)/Builds/${OutFile}";

  # Handle paths
  mkdir -p "$(dirname "${TargetFile}")";

  # Header
  echo '';
  echo -e ' \e[1;37m[ Packed Zip Maker by Adrian DC - 2016 ]\e[0m';
  echo '';

  # Files handling
  Installs=${*};
  for FilePath in ${Installs[*]}; do

    # Target selection
    FileTarget=;
    if [[ "${FilePath}" == *'/system'* ]]; then
      FilePath=$(echo -n "${FilePath}" | tail -1 \
               | sed "s/\x1B\[[0-9;]*[JKmsu]//g" \
               | sed "s/.*\/\([^\[]*.zip\).*/\1/g");
      FileTarget=$(echo "${FilePath}" \
                 | sed "s/.*\(system\/.*\)/\1/g");
    elif [[ "${FilePath}" == *'/proprietary'* ]]; then
      FilePath=$(echo -n "${FilePath}" | tail -1 \
               | sed "s/\x1B\[[0-9;]*[JKmsu]//g" \
               | sed "s/.*\/\([^\[]*.zip\).*/\1/g");
      FileTarget=$(echo "${FilePath}" \
                 | sed "s/.*proprietary\/\(.*\)/system\/\1/g");
    fi;

    # Target copy
    if [ ! -z "${FileTarget}" ]; then
      FileDir=$(dirname "${FileTarget}");
      if [ ! -d "${TmpDir}/${FileDir}" ]; then
        mkdir -p "${TmpDir}/${FileDir}";
      fi;
      if [ -f "${FilePath}" ]; then
        cp "${FilePath}" "${TmpDir}/${FileTarget}";
        FilesList+=("./${FileTarget}");
      fi;
    fi;
  done;

  # Partitions
  SystemPartition=$(androiddevicestarget system);

  # Generate zip, updater-script and include files
  cd "${TmpDir}/";
  mkdir -p ./META-INF/com/google/android/;
  cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_FLASHABLE_ANDROID_BASE}" "${OutFile}.unsigned.zip";
  cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_UPDATER_INSTALL_SYSTEM}" ./META-INF/com/google/android/updater-script;
  sed -i "s/ANDROID_SYSTEM_PARTITION/${SystemPartition//\//\\\/}/" ./META-INF/com/google/android/updater-script;
  zip -g "${TmpDir}/${OutFile}.unsigned.zip" ./META-INF/com/google/android/updater-script;
  rm -rf ./META-INF;

  # Pack zip output
  if [ ! -z "${FilesList[*]}" ]; then
    zip -g "${TmpDir}/${OutFile}.unsigned.zip" "${FilesList[@]}";

    # Zip signature
    signzip "${TmpDir}/${OutFile}.unsigned.zip" "${TmpDir}/${OutFile}";
    cp "${TmpDir}/${OutFile}" "${TargetFile}";

    # End of work
    echo '';
    echo -e " \e[1;37mPackage File:\e[0m ${TargetFile}";
    export PACKAGE_RESULT=${TargetFile};
  fi;
  echo '';

  # End of work
  rm -rf "${TmpDir}";
  cd "${CurDir}";
}

# === Git Zip Maker ===
function gitzip()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo ' Usage: gitzip <commit_sha1> (Git commit files to flashable zip)';
    echo '';
    return;
  fi;

  # Variables
  local file_path;
  local files_list=;
  local status;
  local tmpfile;

  # Files parsing
  tmpfile=$(mktemp);
  git diff-tree --no-commit-id --name-status -r "${1}" > "${tmpfile}";
  while read -r line; do
    status=$(echo "${line}" | awk '{ print $1 }');
    file_path=$(echo "${line}" | awk '{ print $2 }');
    if [[ "${status}" == *'D'* || "${line}" == *'.mk'* ]]; then
      continue;
    fi;
    files_list="${files_list} ${file_path}";
  done < "${tmpfile}";

  # Pack into zip
  packzip "${files_list}";
  rm -f "${tmpfile}";
}

# === OEM Partition Injector ===
function oeminjectorzip()
{
  # Usage
  if [ -z "${1}" ] || [ ! -f "${1}" ]; then
    echo '';
    echo ' Usage: oeminjectorzip <oem_image> (OEM files to flashable injector zip)';
    echo '';
    return;
  fi;

  # Variables
  local cur_dir;
  local oem_file;
  local oem_files;
  local oem_files_list=();
  local oem_folder;
  local oem_image=${1};
  local oem_name;
  local oem_partition;
  local oem_target_file;
  local oem_target_dir;
  local target_file;
  local target_name;
  local tmp_dir;
  local tmp_file;

  # Verify simg2img is installed
  if ! type simg2img >/dev/null 2>&1; then
    echo '';
    echo ' oeminjectorzip: Please install android-tools-fsutils';
    echo '';
    return;
  fi;

  # Mount and prepare the ext4 OEM image
  oem_folder=$(mktemp -d);
  tmp_file=$(mktemp);
  simg2img "${oem_image}" "${tmp_file}";
  sudo mount -t ext4 "${tmp_file}" "${oem_folder}";

  # Extract OEM name
  oem_name=$(basename "${oem_image}");
  oem_name=${oem_name%.*};

  # Initialize variables
  cur_dir=$(pwd);
  tmp_dir=$(mktemp -d);
  target_name="oem-${oem_name}-$(date +'%Y%m%d-%H%M').zip";
  target_file="$(desktoppath)/Builds/${target_name}";

  # Handle paths
  mkdir -p "$(dirname "${target_file}")";

  # Header
  echo '';
  echo -e ' \e[1;37m[ OEM Injector Zip by Adrian DC - 2017 ]\e[0m';
  echo '';

  # Files handling
  oem_files=$(find "${oem_folder}/" -type f -printf '%P\n');
  for oem_file in ${oem_files[*]}; do

    # Target selection
    oem_file=$(echo -n "${oem_file}" | tail -1 \
             | sed "s/\x1B\[[0-9;]*[JKmsu]//g" \
             | sed "s/.*\/\([^\[]*.zip\).*/\1/g");
    oem_target_file=oem/${oem_file};
    oem_target_dir=$(dirname "${oem_target_file}");
    if [ ! -d "${tmp_dir}/${oem_target_dir}" ]; then
      mkdir -p "${tmp_dir}/${oem_target_dir}";
    fi;

    # Target copy
    oem_file=$(readlink -f "${oem_folder}/${oem_file}");
    if [ -f "${oem_file}" ]; then
      cp "${oem_file}" "${tmp_dir}/${oem_target_file}";
      oem_files_list+=("./${oem_target_file}");
    fi;
  done;

  # Pack zip output
  cd "${tmp_dir}/";
  if [ ! -z "${oem_files_list[*]}" ]; then

    # Partitions
    oem_partition=$(androiddevicestarget oem);

    # Generate zip, updater-script and include files
    mkdir -p ./META-INF/com/google/android/;
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_FLASHABLE_ANDROID_BASE}" "${target_name}.unsigned.zip";
    cp "${ANDROID_DEVELOPMENT_SHELL_TOOLS_UPDATER_INSTALL_OEM}" ./META-INF/com/google/android/updater-script;
    sed -i "s/ANDROID_OEM_PARTITION/${oem_partition//\//\\\/}/" ./META-INF/com/google/android/updater-script;
    zip -g "${tmp_dir}/${target_name}.unsigned.zip" ./META-INF/com/google/android/updater-script;
    zip -g "${tmp_dir}/${target_name}.unsigned.zip" "${oem_files_list[@]}";
    rm -rf ./META-INF;

    # Zip signature
    signzip "${tmp_dir}/${target_name}.unsigned.zip" "${tmp_dir}/${target_name}";
    cp "${tmp_dir}/${target_name}" "${target_file}";
    export PACKAGE_RESULT=${target_file};

    # Package result
    echo '';
    echo -e " \e[1;37mPackage File:\e[0m ${target_file}";
  else
    export PACKAGE_RESULT=;
  fi;
  echo '';

  # End of work
  sudo umount "${oem_folder}";
  rm -rf "${tmp_dir}";
  rm -rf "${tmp_file}";
  cd "${cur_dir}";
}
